<?php

namespace Xin\Process\Python;

use Symfony\Component\Process\Process;
use Xin\Capsule\Service;

class Conda extends Service
{

    /**
     * 创建环境
     * @param string $name
     * @param string|null $pythonVersion
     * @return array
     */
    public function create(string $name, string $pythonVersion = null): array
    {
        $commands = [
            "create", "-n", $name
        ];
        if ($pythonVersion !== null) {
            $commands[] = "python=" . $pythonVersion;
        }
        $commands = array_merge($commands, ["-y", "--json",]);

        $process = $this->makeProcess($commands);
        $result = $process->mustRun()->getOutput();
        return json_decode($result, true);
    }

    /**
     * 移除环境
     * @param string $name
     * @return array
     */
    public function remove(string $name): array
    {
        $commands = [
            "remove", "-n", $name,
            '--all', "-y", "--json",
        ];
        $process = $this->makeProcess($commands);
        $result = $process->mustRun()->getOutput();
        if (!$result) {
            return [];
        }

        return json_decode($result, true);
    }

    /**
     * 获取环境列表
     * @return array
     */
    public function envs(): array
    {
        $result = $this->info();

        $envs = [];
        foreach ($result['envs'] as $envPath) {
            if (strpos($envPath, "/envs/") === false) {
                $envName = 'base';
            } else {
                $envName = basename($envPath);
            }
            $envs[$envName] = $envPath;
        }

        return $envs;
    }

    /**
     * 获取环境详情
     * @return array
     */
    public function info(): array
    {
        $process = $this->makeProcess("info --json");
        $result = $process->mustRun()->getOutput();
        return json_decode($result, true);
    }

    /**
     * 搜索包名
     * @param string|null $name
     * @param array $options
     * @return array
     */
    public function lists(string $name = null, array $options = [])
    {
        $commands = [
            "list", "-n", $name,
            '--all', "-y", "--json",
        ];
        $name && $commands = array_merge($commands, ["-n", $name]);
        isset($options['search']) && $commands[] = "^" . $options['search'];
        isset($options['export']) && $commands = array_merge($commands, ["-n", $name]);

        $process = $this->makeProcess($commands);
        $result = $process->mustRun()->getOutput();
        if (!$result) {
            return [];
        }

        return json_decode($result, true);
    }

    /**
     * 安装包
     * @param string $pkgs
     * @param bool $compile
     * @return mixed
     */
    public function install(string $pkgs, bool $compile = true)
    {
        $commands = [
            "install", $compile ? "-c" : '', $pkgs
        ];
        $commands = array_filter($commands);
        $process = $this->makeProcess($commands);
        $result = $process->mustRun()->getOutput();
        return json_decode($result, true);
    }

    /**
     * 卸载包
     * @param string $pkgs
     * @return mixed
     */
    public function uninstall(string $pkgs)
    {
        $commands = [
            "install", $pkgs
        ];
        $commands = array_filter($commands);
        $process = $this->makeProcess($commands);
        $result = $process->mustRun()->getOutput();
        return json_decode($result, true);
    }

    /**
     * @param string|array $shellCommandline
     * @return Process
     */
    protected function makeProcess($shellCommandline): Process
    {
        if (is_array($shellCommandline)) {
            $shellCommandline = implode(" ", $shellCommandline);
        }

        $condaPath = $this->getCondaPath();
        $finalShellCommandline = implode(" ", [
            $condaPath,
            $shellCommandline
        ]);
        return tap(Process::fromShellCommandline($finalShellCommandline), function (Process $process) {
            var_dump($process->getCommandLine());
        });
    }

    /**
     * @return string
     */
    public function getCondaPath(): string
    {
        return $this->getConfig('path', 'conda');
    }


    /**
     * @inerhitDoc
     */
    public static function makeInstance()
    {
        return new static([
            'path' => 'conda',
        ]);
    }
}
